package pxe

import (
	"flag"
	"fmt"
	"github.com/bitly/go-simplejson"
	"github.com/pyroscope-io/pyroscope/pkg/agent/profiler"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"time"
)

func ServeHTTP(body []byte, os string, timing string) {
	res, _ := simplejson.NewJson(body)

	if os == "ubuntu" {
		InstallSucces(body, timing)
	} else {
		fmt.Println(res.Get("name").MustString())
		fmt.Println(res.Get("event_type").MustString())
		fmt.Println(res.Get("result").MustString())
	}
}

func Route(osType string, timing string) {

}

func InstallSucces(body []byte, timing string) {

	fmt.Println(string(body), timing)
}

func Test() {

	/*conn := &ipmi.Connection{
		Path:      "ipmitool",
		Hostname:  "10.1.104.9",
		Port:      623,
		Username:  "root",
		Password:  "wlza123!",
		Interface: "lanplus",
	}
	ipmiclient, err1 := ipmi.NewClient(conn)
	if err1 != nil {
		fmt.Println(err1)
	}
	ipmiclient.Open()
	a, err := ipmiclient.DeviceID()
	if err != nil {
		fmt.Println(err)
	}
	ipmi2client, err2 := ipmi2.NewClient("10.1.104.9", 623, "root", "wlza123!")

	if err2 != nil {
		fmt.Println(err2)
	}
	ipmi2client.Interface = ipmi2.InterfaceLanplus
	err3 := ipmi2client.ConnectAuto()
	if err3 != nil {
		fmt.Println(err3)
	}
	b, _ := ipmi2client.GetDeviceID()

	fmt.Println("b ", b.Format())
	fmt.Println(a)*/

}

/*
	func SetGroupMap(chat *simplejson.Json) {
		GroupMap = make(map[string]interface{})
		for _, v := range chat.Get("webhook_list").MustArray() {
			for group, serverList := range v.(map[string]interface{}) {
				GroupMap[group] = serverList
			}
		}
	}

	func GetAccessToken(handler *Handler, token map[string]string) {
		type JSON struct {
			AccessToken string `json:"access_token"`
		}
		var corpId, corpSecret, qyurl string
		var body []byte
		var bodyErr, getErr, jsonErr error
		var req *http.Response
		client := &http.Client{}

		for {
			tokenMap := make(map[string]string)
			for _, v := range handler.wechat.Get("webhook_list").MustArray() {
				for group, serviceList := range v.(map[string]interface{}) {
					GroupMap[group] = serviceList
					ZapLog.Info("webhook-alarm",
						zap.Any("group:", group),
						zap.Any("serviceList", serviceList),
					)
					corpId = PHandler.wechat.Get(group).Get("corp_id").MustString()
					corpSecret = PHandler.wechat.Get(group).Get("corp_secret").MustString()

					if value, ok := tokenMap[(corpId + corpSecret)]; ok {
						token[group] = value
						ZapLog.Info("webhook-alarm",
							zap.Any("TokenReuse:", true),
							zap.Any("AlarmGroup:", group),
							zap.Any("WechatToken", value),
						)
						break
					}

					qyurl = fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s", corpId, corpSecret)
					req, getErr = client.Get(qyurl)
					if getErr != nil {
						panic(getErr)
					}

					body, bodyErr = ioutil.ReadAll(req.Body)
					if bodyErr != nil {
						panic(bodyErr)
					} else {
						req.Body.Close()
					}

					ZapLog.Info("webhook-alarm",
						zap.Any("AlarmGroup:", group),
						zap.Any("WechatToken", string(body)),
					)

					var jsonStr JSON
					jsonErr = json.Unmarshal(body, &jsonStr)
					if jsonErr != nil {
						panic(jsonErr)
					}
					token[group] = jsonStr.AccessToken
					tokenMap[(corpId + corpSecret)] = jsonStr.AccessToken
				}
			}

			time.Sleep(1 * time.Hour)
		}
	}

	func SearchSrevice(serviceName string, groupmap map[string]interface{}) []string {
		var regexpBool bool
		var groupSlice []string

		for group, serviceList := range groupmap {
			s := reflect.ValueOf(serviceList)
			for serviceListNum, countNum := 0, s.Len(); serviceListNum < countNum; serviceListNum++ {
				serviceNameRegexp := s.Index(serviceListNum).Elem().String()
				regexpBool, _ = regexp.MatchString(serviceNameRegexp, serviceName)
				if regexpBool {
					groupSlice = append(groupSlice, group)
					break
				}
			}

		}
		return groupSlice
	}

	func SendMessage(agentid, totag, msg string, token string, groupName string, timing string) bool {
		req := map[string]interface{}{
			"agentid": agentid,
			"msgtype": "text",
			"totag":   totag,
			"text": map[string]interface{}{
				"content": msg,
			},
			"safe": 0,
		}
		url := []byte("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=")
		url = append(url, []byte(token)...)

		return HttpPostjson(string(url), req, groupName, timing)
	}

	func HttpPostjson(url string, data map[string]interface{}, groupName string, timing string) bool {
		jsonData, err := json.Marshal(data)
		if err != nil {
			ZapLog.Error("webhook-alarm",
				zap.Any("TraceId", timing),
				zap.Any("GroupName", groupName),
				zap.Any("JsonMarshalError", err),
			)
			return false
		} else {
			ZapLog.Info("webhook-alarm",
				zap.Any("TraceId", timing),
				zap.Any("GroupName", groupName),
				zap.Any("WechatBody", string(jsonData)),
			)
		}
		resp, err := http.Post(url, "application/json", bytes.NewReader(jsonData))
		if err != nil {
			ZapLog.Error("webhook-alarm",
				zap.Any("TraceId", timing),
				zap.Any("GroupName", groupName),
				zap.Any("PostError", err),
			)
			return false
		}
		body, err := ioutil.ReadAll(resp.Body)
		ZapLog.Info("webhook-alarm",
			zap.Any("TraceId", timing),
			zap.Any("GroupName", groupName),
			zap.Any("WechatResponse", string(body)),
		)
		defer resp.Body.Close()
		return true
	}
*/
func Parse() {
	fmt.Println(welcome)
	time.Sleep(2 * time.Second)
	var scope = flag.Bool("scope", false, "性能监测开关")
	var conf, scopeServerAddr, logType, rabbitmqAddr, rabbitmqUser, rabbitmqPass, rabbitmqVhost, mongoAddr string

	flag.StringVar(&conf, "conf", "wechat.conf", "指定配置文件地址")
	flag.StringVar(&scopeServerAddr, "s", "localhost:4040", "指定pyroscope服务端地址")
	flag.StringVar(&rabbitmqAddr, "mqaddr", "localhost", "指定rabbitmq地址")
	flag.StringVar(&rabbitmqUser, "mquser", "admin", "指定rabbitmq用户")
	flag.StringVar(&rabbitmqPass, "mqpass", "admin", "指定rabbitmq密码")
	flag.StringVar(&rabbitmqVhost, "mqvhost", "/alarm", "指定mongodb地址")
	flag.StringVar(&mongoAddr, "mgaddr", "mongodb://localhost:27017", "指定vhost")
	flag.StringVar(&logType, "logType", "", "指定日志类型，container: 控制台日志，否则日志输出到控制台及文件")
	flag.Parse()

	//time.Duration = 1000 000 000

	encoderConfig := zapcore.EncoderConfig{
		TimeKey:       "time",
		LevelKey:      "level",
		NameKey:       "logger",
		CallerKey:     "caller",
		MessageKey:    "serviceName",
		StacktraceKey: "stacktrace",
		LineEnding:    zapcore.DefaultLineEnding,
		EncodeLevel:   zapcore.CapitalLevelEncoder,
		EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
		},
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.FullCallerEncoder,
	}

	atom := zap.NewAtomicLevelAt(zap.InfoLevel)
	config := zap.Config{}

	OutputPaths := []string{"stdout", "./log/alarm.log"}
	ErrorOutputPaths := []string{"stderr", "./log/alarm.log"}
	if logType == "Container" {
		OutputPaths = []string{"output"}
		ErrorOutputPaths = []string{"outerr"}
	}

	config = zap.Config{
		Level:            atom,
		Development:      false,
		DisableCaller:    true,
		Encoding:         "console", //json or console
		EncoderConfig:    encoderConfig,
		OutputPaths:      OutputPaths,
		ErrorOutputPaths: ErrorOutputPaths,
	}

	var err error
	ZapLog, err = config.Build()
	if err != nil {
		panic(fmt.Sprintf("ZapLog init failed: %v", err))
	} else {
		ZapLog.Info("webhook-alarm",
			zap.Any("ZapLogStatus", "success"),
		)
	}

	if *scope {
		scopeServerAddr := fmt.Sprintf("http://%s", scopeServerAddr)
		_, err := profiler.Start(profiler.Config{
			ApplicationName: "webhook-alarm",
			ServerAddress:   scopeServerAddr,
		})
		if err != nil {
			ZapLog.Error("webhook-alarm",
				zap.Any("ScopeStartError", err),
			)
		} else {
			ZapLog.Info("webhook-alarm",
				zap.Any("ScopeStartStatus", "success"),
			)
		}
	}

	/*	var parseErr error
		PHandler.pxeReport, parseErr = simplejson.NewJson(wechatConf)
		if parseErr != nil {
			ZapLog.Error("webhook-alarm",
				zap.Any("WechatConfParseErr", parseErr),
			)
			panic(parseErr)
		}

		//Set_GroupMap(PHandler.wechat)
		GroupMap = make(map[string]interface{})
		go GetAccessToken(PHandler, token)
		CreateRabbitmqQueue(rabbitmqAddr, *mqPort, rabbitmqUser, rabbitmqPass, rabbitmqVhost)
		instanceRPool = initrabbitmq(rabbitmqAddr, *mqPort, rabbitmqUser, rabbitmqPass, rabbitmqVhost)
		instanceConsumePool = initConsumerabbitmq(rabbitmqAddr, *mqPort, rabbitmqUser, rabbitmqPass, rabbitmqVhost)
		go Consume("sentry")
		go Consume("skywalking")
		MongodbClient, err = ConnMongodb(mongoAddr, 10, 100)
		if err != nil {
			ZapLog.Error("webhook-alarm",
				zap.Any("ConnMongoDbErr", err),
			)
			panic(err)
		}*/
}

/*
	func initrabbitmq(mqaddr string, mqport int, mquser string, mqpass string, mqvhost string) *kelleyRabbimqPool.RabbitPool {
		oncePool.Do(func() {
			instanceRPool = kelleyRabbimqPool.NewProductPool()
			err := instanceRPool.Connect(mqaddr, mqport, mquser, mqpass, mqvhost)
			if err != nil {
				fmt.Println(err)
			}
		})
		return instanceRPool
	}

	func PushlishPool(msg string, alarmType string, serviceName string, timing string) {
		data := kelleyRabbimqPool.GetRabbitMqDataFormat("alarm", kelleyRabbimqPool.EXCHANGE_TYPE_DIRECT, alarmType, alarmType, msg, serviceName, timing)
		err := instanceRPool.Push(data)
		if err != nil {
			ZapLog.Error("webhook-alarm",
				zap.Any("TraceId", timing),
				zap.Any("ServiceName", serviceName),
				zap.Any("MsgPushError", err),
			)
		}
	}

	func initConsumerabbitmq(mqaddr string, mqport int, mquser string, mqpass string, mqvhost string) *kelleyRabbimqPool.RabbitPool {
		onceConsumePool.Do(func() {
			instanceConsumePool = kelleyRabbimqPool.NewConsumePool()
			//instanceConsumePool.SetMaxConsumeChannel(100)
			err := instanceConsumePool.Connect(mqaddr, mqport, mquser, mqpass, mqvhost)
			if err != nil {
				fmt.Println(err)
			}
		})
		return instanceConsumePool
	}

	func Consume(queueName string) {
		nomrl := &kelleyRabbimqPool.ConsumeReceive{
			ExchangeName: "alarm", //交换机名称
			ExchangeType: kelleyRabbimqPool.EXCHANGE_TYPE_DIRECT,
			Route:        "",
			QueueName:    queueName,
			IsTry:        true,  //是否重试
			IsAutoAck:    false, //自动消息确认
			MaxReTry:     5,     //最大重试次数
			EventFail: func(code int, e error, data []byte) {
				fmt.Printf("error:%s", e)
			},
			EventSuccess: func(data []byte, header map[string]interface{}, retryClient kelleyRabbimqPool.RetryClientInterface, appId string, msgId string, queueName string) bool { //如果返回true 则无需重试
				if SentMsg(data, appId, msgId, queueName) {
					_ = retryClient.Ack()
					return true
				} else {
					return false
				}
			},
		}
		instanceConsumePool.RegisterConsumeReceive(nomrl)
		err := instanceConsumePool.RunConsume()
		if err != nil {
			fmt.Println(err)
		}
	}

	func CreateRabbitmqQueue(mqaddr string, mqport int, mquser string, mqpass string, mqvhost string) {
		mqAddr := fmt.Sprintf("amqp://%s:%s@%s:%d%s", mquser, mqpass, mqaddr, mqport, mqvhost)
		conn, err := amqp.Dial(mqAddr)
		failOnError(err, "Failed to connect to RabbitMQ")
		defer conn.Close()
		ch, err := conn.Channel()
		failOnError(err, "Failed to open a channel")
		defer ch.Close()
		err = ch.ExchangeDeclare("alarm", "direct", true, false, false, false, nil)
		failOnError(err, "Failed to declare an exchange")

		_, err = ch.QueueDeclare("skywalking", true, false, false, false, nil)
		failOnError(err, "Failed to declare an queue")
		err = ch.QueueBind("skywalking", "skywalking", "alarm", false, nil)
		failOnError(err, "Bind queue to exchange failure")

		_, err = ch.QueueDeclare("sentry", true, false, false, false, nil)
		failOnError(err, "Failed to declare an queue")
		err = ch.QueueBind("sentry", "sentry", "alarm", false, nil)
		failOnError(err, "Bind queue to exchange failure")
	}

	func SentMsg(msg []byte, appId string, msgId string, queueName string) bool {
		switch queueName {
		case "sentry":
			groupSlice := SearchSrevice(appId, GroupMap)
			if len(groupSlice) == 0 {
				ZapLog.Warn("webhook-alarm",
					zap.Any("TraceId", msgId),
					zap.Any("ServiceName", appId),
					zap.Any("MatchGroupError", "does not belong to any group"),
				)
			} else {
				for _, groupNameSub := range groupSlice {
					limit.Wait(contextValue)
					totag := PHandler.wechat.Get(groupNameSub).Get("to_tag").MustString()
					agentid := PHandler.wechat.Get(groupNameSub).Get("agent_id").MustString()
					tokens := token[groupNameSub]
					if sentStatus := SendMessage(agentid, totag, string(msg), tokens, groupNameSub, msgId); !sentStatus {
						return false
					}
				}
			}

		case "skywalking":
			groupSlice := SearchSrevice(appId, GroupMap)
			if len(groupSlice) == 0 {
				ZapLog.Warn("webhook-alarm",
					zap.Any("TraceId", msgId),
					zap.Any("ServiceName", appId),
					zap.Any("MatchGroupError", "does not belong to any group"),
				)
			} else {
				for _, groupNameSub := range groupSlice {
					limit.Wait(contextValue)
					totag := PHandler.wechat.Get(groupNameSub).Get("to_tag").MustString()
					agentid := PHandler.wechat.Get(groupNameSub).Get("agent_id").MustString()
					tokens := token[groupNameSub]
					if sentStatus := SendMessage(agentid, totag, string(msg), tokens, groupNameSub, msgId); !sentStatus {
						return false
					}
				}
			}
		default:
			fmt.Println("我也不知道干啥，就想有default")
		}
		return true
	}
*/
func failOnError(err error, msg string) {
	if err != nil {
		ZapLog.Warn("webhook-alarm",
			zap.Any("Msg", msg),
			zap.Any("Err", err),
		)
	}
}

/*func SetSentryMsgFormat(alarmType string, senMsg SentryMsg) (msg string) {
	return fmt.Sprintf("Alarm_type: %s\nProject:  %s\nIssue_service:  %s\nIssue_id:  %s\nIssue_message:  %s\nIssue_culprit:  %s\nIssue_url:  %s",
		alarmType, senMsg.Project, senMsg.Issue_service, senMsg.Issue_id, senMsg.Issue_message, senMsg.Issue_culprit, senMsg.Issue_url)
}

func SetSkyMsgFormat(alarmType string, skyMsg SkyMsg) (msg string) {
	return fmt.Sprintf("Alarm_type: %s\nScope:  %s\nName:  %s\nRuleName:  %s\nAlarmMessage:  %s",
		alarmType, skyMsg.Scope, skyMsg.Name, skyMsg.RuleName, skyMsg.AlarmMessage)
}

func ConnMongodb(uri string, timeout time.Duration, num uint64) (*mongo.Client, error) {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	opt := options.Client().ApplyURI(uri)
	opt.SetMaxPoolSize(num)
	opt.SetMinPoolSize(10)
	client, err := mongo.Connect(ctx, opt)
	if err != nil {
		ZapLog.Error("webhook-alarm",
			zap.Any("ConnMongDbErr", err),
		)
		return nil, err
	}
	return client, nil

}

func (doc *SentryMsg) PushSentryMsgToMongoDb(c *mongo.Client, alarmType string) {
	collection := c.Database("alarm").Collection(alarmType)
	insertResult, err := collection.InsertOne(context.TODO(), *doc)
	if err != nil {
		ZapLog.Error("webhook-alarm",
			zap.Any("TraceId", doc.TraceId),
			zap.Any("ServiceName", doc.Issue_service),
			zap.Any("InsertMongoDbErr", err),
		)
	} else {
		ZapLog.Info("webhook-alarm",
			zap.Any("TraceId", doc.TraceId),
			zap.Any("ServiceName", doc.Issue_service),
			zap.Any("InsertMongoDbSucess", insertResult.InsertedID),
		)
	}

}

func (doc *SkyMsg) PushSkyMsgToMongoDb(c *mongo.Client, alarmType string) {
	collection := c.Database("alarm").Collection(alarmType)
	insertResult, err := collection.InsertOne(context.TODO(), *doc)
	if err != nil {
		ZapLog.Error("webhook-alarm",
			zap.Any("TraceId", doc.TraceId),
			zap.Any("RuleName", doc.RuleName),
			zap.Any("InsertMongoDbErr", err),
		)
	} else {
		ZapLog.Info("webhook-alarm",
			zap.Any("TraceId", doc.TraceId),
			zap.Any("RuleName", doc.RuleName),
			zap.Any("InsertMongoDbSucess", insertResult.InsertedID),
		)
	}
}

func PushMsgToMongoDb(c *mongo.Client, doc []byte, alarmType string, timing string) {
	postMongo := []byte("{\"TraceId\":\"")
	postMongo = append(postMongo, []byte(timing)...)
	postMongo = append(postMongo, []byte("\",\"Msg\":")...)
	postMongo = append(postMongo, doc...)
	postMongo = append(postMongo, []byte("}")...)

	res := &struct {
		TraceId string
		Msg     string
	}{
		timing,
		string(doc),
	}

	collection := c.Database("alarm").Collection(alarmType)
	insertResult, err := collection.InsertOne(context.TODO(), *res)
	if err != nil {
		ZapLog.Error("webhook-alarm",
			zap.Any("TraceId", timing),
			zap.Any("Type", "raw faild"),
			zap.Any("RawMsgInsertMongoDbErr", err),
		)
	} else {
		ZapLog.Info("webhook-alarm",
			zap.Any("TraceId", timing),
			zap.Any("Type", "raw message"),
			zap.Any("RawMsgInsertMongoDbSucess", insertResult.InsertedID),
		)



	}

}
*/
